package org.example.netty.test.nio.java;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.net.URL;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;

/**
 * @author zp
 * @version 1.0
 * @description: IO 相关的工具类
 * IO模型：
 * 一、同步阻塞IO：在应用调用recvfrom读取数据时，其系统调用直到数据包到达且被复制到应用缓冲区中或者发送错误时才返回，
 * 在此期间一直会等待，进程从调用到返回这段时间内都是被阻塞的称为阻塞IO；（简单来说 就是在读取或者写入的时候只能等待 线程无法去干其他的事情）
 * 二、同步非阻塞IO：非阻塞IO是在应用调用recvfrom读取数据时，如果该缓冲区没有数据的话，就会直接返回一个EWOULDBLOCK错误，
 * 不会让应用一直等待中。在没有数据的时候会即刻返回错误标识，那也意味着如果应用要读取数据就需要不断的调用recvfrom请求，
 * 直到读取到它数据要的数据为止。（简单来说 就是在读取或者写入的时候会立马返回如果成功就继续操作 如果未完成返回错误 线程在这个期间可以去干其他的事情，
 * 不会阻塞线程的操作，但是需要轮训查看状态）
 * 三、IO复用：进程通过将一个或多个fd传递给select，阻塞在select操作上，select帮我们侦测多个fd是否准备就绪，
 * 当有fd准备就绪时，select返回数据可读状态，应用程序再调用recvfrom读取数据。（简单来说 就是一个线程可以监控多个请求 当其中任何一个请求完成操作，
 * 复用IO就会即可返回 通知有数据完成 可以进行后续操作 这样可以解决线程 无需每个请求用一个线程处理 只需要轮训select线程 查看有无事件完成处理）
 * 总结：复用IO的基本思路就是通过slect或poll、epoll 来监控多fd ，来达到不必为每个fd创建一个对应的监控线程，从而减少线程资源创建的目的。
 *
 * 四、信号驱动IO： IO复用模型里面的select虽然可以监控多个fd了，但select其实现的本质上还是通过不断的轮询fd来监控数据状态，
 * 因为大部分轮询请求其实都是无效的，所以信号驱动IO意在通过这种建立信号关联的方式，实现了发出请求后只需要等待数据就绪的通知即可，
 * 这样就可以避免大量无效的数据状态轮询操作。（简单来说 就是在事件触发时间 注册一个事件到select当中 当事件完成操作 发出回调通知 可以直接去处理操作，
 * 无需轮训等待 线程在未收到回调事件 可以去干别的事情）
 * 总结： IO复用模型里面的select虽然可以监控多个fd了，但select其实现的本质上还是通过不断的轮询fd来监控数据状态，
 * 因为大部分轮询请求其实都是无效的，所以信号驱动IO意在通过这种建立信号关联的方式，实现了发出请求后只需要等待数据就绪的通知即可，
 * 这样就可以避免大量无效的数据状态轮询操作。
 * 异步非阻塞IO：应用告知内核启动某个操作，并让内核在整个操作完成之后，通知应用，这种模型与信号驱动模型的主要区别在于，
 * 信号驱动IO只是由内核通知我们合适可以开始下一个IO操作，而异步IO模型是由内核通知我们操作什么时候完成。（简单来说 就是在发生事情的时候 交个另一个线程去完成工作，
 * 对本线程无任何影响 只需要接收发送事件 其他的事情多会在异步线程完成操作）
 * 异步IO的优化思路是解决了应用程序需要先后发送询问请求、发送接收数据请求两个阶段的模式，在异步IO的模式下，只需要向内核发送一次请求就可以完成状态询问和数拷贝的所有操作。
 * @date 2023/2/20 19:12
 */
public class IOUtil {
    public static String getResourcePath(String sourcePath) {
        URL url = IOUtil.class.getResource("/" + sourcePath);
        if (url != null) {
            return url.getPath();
        }
        return null;
    }

    public static String builderResourcePath(String destPath) {
        URL uri = IOUtil.class.getResource("/");
        return uri.getPath()+destPath;
    }

    public static void closeQuietly(FileChannel outchannel) {
        if(outchannel!=null){
            try{
                outchannel.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    public static void closeQuietly(FileOutputStream fileOutputStream) {
        if(fileOutputStream!=null){
            try{
                fileOutputStream.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    public static void closeQuietly(SocketChannel socketChannel) {
        if(socketChannel!=null){
            try{
                socketChannel.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    public static void closeQuietly(FileInputStream fileInputStream) {
        if(fileInputStream!=null){
            try{
                fileInputStream.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    public static long getFormatFileSize(long fileLength) {
        return fileLength/1024;
    }
}
